package com.user.service.Impl;

import com.common.domain.User;
import com.common.utils.MD5Utils;
import com.common.utils.TimeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.user.dao.UserDao;
import com.user.exception.MsgException;
import com.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author Elias
 * @version 1.0
 * @date 2021-06-02 17:05
 * @description
 * @copyright 2021
 */
@Service
public class UserServiceImpl implements UserService {
  @Autowired private UserDao userDao;

  @Autowired private StringRedisTemplate stringRedisTemplate;

  @Autowired private ObjectMapper objectMapper;

  @Override
  public boolean checkUserName(String userName) {
    int num = userDao.selectCount(new User(null, userName, null, null, null, null));
    return num == 0;
  }

  @Override
  public void registerUser(
      User user, Errors error, String password2, String valistr, String token) {
    // 密码一致性
    if (!user.getUserPassword().equals(password2)) {
      throw new MsgException("两次密码不一致");
    }
    //    验证码非空
    if (StringUtils.isEmpty(valistr)) {
      throw new MsgException("验证码不允许为空");
    }
    //    验证码正确性
    if (!valistr.equalsIgnoreCase(stringRedisTemplate.opsForValue().get("token"))) {
      throw new MsgException("验证码不对");
    }
    //    进行bean校验
    List<FieldError> errors = error.getFieldErrors();
    if (errors.isEmpty()) {
      //      bean校验无误，进行用户名重复性校验
      try {
        user.setUserId(UUID.randomUUID().toString());
        user.setUserPassword(MD5Utils.md5(user.getUserPassword()));
        userDao.insertSelective(user);
        //        注册完成后删除redis中的缓存验证码
        stringRedisTemplate.delete(TimeUtils.cutTimeStamp(token));
        stringRedisTemplate.delete(token);
      } catch (DuplicateKeyException e) {
        e.printStackTrace();
        throw new MsgException(e.getMessage());
      }
    } else {
      throw new MsgException(errors.get(0).getDefaultMessage());
    }
  }

  @Override
  public String loginUser(User user, String valistr, String token) {
    //    先进行验证码校验
    try {
      String valicode = stringRedisTemplate.opsForValue().get(token);
      if (valicode == null || !valicode.equalsIgnoreCase(valistr)) {
        throw new MsgException("验证码不正确");
      }
      //    传过来请求的密码没加密
      user.setUserPassword(MD5Utils.md5(user.getUserPassword()));
      List<User> users = userDao.selectUser(user);
      if (users.size() == 0 || users.isEmpty()) {
        return null;
      }
      String ticket = "EM_TICKET_" + users.get(0).getUserName();
      String value = objectMapper.writeValueAsString(users.get(0));
      stringRedisTemplate.opsForHash().put(ticket, "data", value);
      stringRedisTemplate.opsForHash().put(ticket, "timestamp", TimeUtils.getTimeStamp());
      stringRedisTemplate.expire(ticket, 30, TimeUnit.MINUTES);
      stringRedisTemplate.delete(token);
      return ticket + stringRedisTemplate.opsForHash().get(ticket, "timestamp");
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  public String loginState(String ticket) {
    String key = TimeUtils.cutTimeStamp(ticket);
    String timestamp = TimeUtils.subTimeStamp(ticket);
    if (timestamp != null
        && timestamp.equals(stringRedisTemplate.opsForHash().get(key, "timestamp"))) {
      return (String) stringRedisTemplate.opsForHash().get(key, "data");
    }
    return null;
  }

  @Override
  public void deleteTicket(String ticket) {
    String key = TimeUtils.cutTimeStamp(ticket);
    stringRedisTemplate.delete(key);
  }

  @Override
  public String loginUser(User user) {
    // cookie保存的是加密密码，不需要再次MD5
    // TODO 需要进行时间校验
    try {
      String key = "AUTOLOGIN" + user.getUserName();
      String value = String.valueOf(System.currentTimeMillis());
      stringRedisTemplate.opsForList().leftPush(key, value);
      stringRedisTemplate.expire(key, 30, TimeUnit.MINUTES);
      List<String> lst = stringRedisTemplate.opsForList().range(key, 0, -1);
      if (lst.isEmpty() || lst.size() == 0) {
        return null;
      }
      if (lst.size() > 1) {
        String oldValue = stringRedisTemplate.opsForList().rightPop(key);
        if (oldValue == null || Long.parseLong(value) - Long.parseLong(oldValue) < 50000) {
          return null;
        }
      }
      List<User> users = userDao.selectUser(user);
      if (users.size() == 0) {
        throw new MsgException("用户名或密码错误");
      }
      //      找到用户名进行登录
      String token = "EM_TICKET_" + users.get(0).getUserName();
      String data = objectMapper.writeValueAsString(users.get(0));
      stringRedisTemplate.opsForHash().put(token, "data", data);
      stringRedisTemplate.opsForHash().put(token, "timestamp", TimeUtils.getTimeStamp());
      stringRedisTemplate.expire(token, 30, TimeUnit.MINUTES);
      return token + stringRedisTemplate.opsForHash().get(token, "timestamp");
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  public Integer queryUserType(String ticket) {
    ticket = ticket.substring(0, ticket.length() - 13);
    String data = (String) stringRedisTemplate.opsForHash().get(ticket, "data");
    try {
      User user = objectMapper.readValue(data, User.class);
      return user.getUserType();
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }
}
